Horizontal Pod Autoscaling と Cluster Autoscaler を EKSに設定してみた
はじめに
おはようございます、加藤です。CKAを受けようと思っていましたが、勉強する時間もとれず、申し込みが英語でまるで理解できなかったのでチキって辞めました。 というわけで、EKSでHorizontal Pod Autoscaling と Cluster Autoscaler を設定してみました。
説明
Horizontal Pod Autoscaling
Horizontal Pod Autoscaler - Kubernetes
Horizontal Pod Autoscaling(以降、HPA)はCPU負荷などメトリクスに応じてDeploymentに命令を送りReplica数を制御する機能です。 コンテナに与えるリソースは変えずに、同時実行を増減させます。つまり、スケールイン/アウトを行います。
Horizontal Pod Autoscaler で利用可能なメトリクスは下記があります。 1
- Resource
- CPU/メモリのリソース
- Object
- Kubernetes Objectのメトリクス(例: Ingressのhits/s)
- Pods
- Podのメトリクス(例: Podのコネクション数
- External
- Kubernetes外のメトリクス(例: LBのQPS、Cloud Pub/Subの溜まっているメッセージ数)
そして、EKSでHPAを使うには、Kubernetes Metrics Serverをインストールする必要があります。
Cluster Autoscaler
Cluster Autoscaler(以降、CA)はWorkerNodesのAutoscalingを行う機能です。この機能は現在NodeのCPU負荷などではなく、Pending状態のPodを検知してスケールアウトを行います。 EKSのWorkerNodesはAmazon EC2 Auto Scaling(以降、EC2 Auto Scaling)で構築しますが、スケーリングポリシーは設定しません。 CAからEC2 Auto Scalingに対して、希望するキャパシティを指定する事でAutoscalingを行います。
やってみた
前提
- EKS環境が構築されている
- Helmがインストールされている
Metrics Server
EKSにMetrics Serverをインストールします。
helm install stable/metrics-server --version 2.6.0 --name metrics-server --namespace kube-system
HPA
DeploymentとHorizontalPodAutoscalerのマニフェストファイルを作成してapplyします。
apiVersion: apps/v1 kind: Deployment metadata: name: sample-deployment spec: replicas: 3 selector: matchLabels: app: sample-app template: metadata: labels: app: sample-app spec: containers: - image: busybox name: sample-deployment command: ["dd", "if=/dev/zero", "of=/dev/null"] # CPUを100%使うように resources: requests: memory: "64Mi" cpu: "250m" limits: memory: "128Mi" cpu: "500m" --- apiVersion: autoscaling/v2beta1 kind: HorizontalPodAutoscaler metadata: name: sample-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: sample-deployment minReplicas: 1 maxReplicas: 30 metrics: - type: Resource resource: name: cpu targetAverageUtilization: 50
kubectl apply -f sample-hpa.yaml
メトリクスの取得状況を確認します。
kubectl get hpa -w NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE sample-hpa Deployment/sample-deployment <unknown>/50% 1 30 3 47s sample-hpa Deployment/sample-deployment 199%/50% 1 30 3 90s
最初は、と表示されますが、しばらく待っているとメトリクスが表示されます。表示されたら、Ctrl+C
で抜けてください。
Pending状態になっているPodが存在するか確認します。
kubectl get po | grep Pending
もし、Nodesに十分なリソースがあり全て起動している場合は、下記の値を増やしてください。
maxReplicas: 30
WorkerNodesのIAMロール
CAはWorkerNodesの上で動き、CAからEC2 Auto Scalingの制御を行います。つまりWorkerNodesのIAMロールにアクセスする権限を与える必要があります。 下記のIAMポリシーを作成して、アタッチします。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "autoscaling:DescribeAutoScalingGroups", "autoscaling:DescribeAutoScalingInstances", "autoscaling:DescribeTags", "autoscaling:SetDesiredCapacity", "autoscaling:TerminateInstanceInAutoScalingGroup" ], "Resource": "*" } ] }
なお、autoscaling:DescribeTags
は--node-group-auto-discovery
でAuto Scaling Groupを自動検出する時以外は本来不要です。
autoscaler/README.md at master · kubernetes/autoscaler
CA
CAのマニフェストファイルを作成します。
apiVersion: v1 kind: ServiceAccount metadata: labels: k8s-addon: cluster-autoscaler.addons.k8s.io k8s-app: cluster-autoscaler name: cluster-autoscaler namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRole metadata: name: cluster-autoscaler labels: k8s-addon: cluster-autoscaler.addons.k8s.io k8s-app: cluster-autoscaler rules: - apiGroups: [""] resources: ["events", "endpoints"] verbs: ["create", "patch"] - apiGroups: [""] resources: ["pods/eviction"] verbs: ["create"] - apiGroups: [""] resources: ["pods/status"] verbs: ["update"] - apiGroups: [""] resources: ["endpoints"] resourceNames: ["cluster-autoscaler"] verbs: ["get", "update"] - apiGroups: [""] resources: ["nodes"] verbs: ["watch", "list", "get", "update"] - apiGroups: [""] resources: [ "pods", "services", "replicationcontrollers", "persistentvolumeclaims", "persistentvolumes", ] verbs: ["watch", "list", "get"] - apiGroups: ["extensions"] resources: ["replicasets", "daemonsets"] verbs: ["watch", "list", "get"] - apiGroups: ["policy"] resources: ["poddisruptionbudgets"] verbs: ["watch", "list"] - apiGroups: ["apps"] resources: ["statefulsets"] verbs: ["watch", "list", "get"] - apiGroups: ["storage.k8s.io"] resources: ["storageclasses"] verbs: ["watch", "list", "get"] --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: Role metadata: name: cluster-autoscaler namespace: kube-system labels: k8s-addon: cluster-autoscaler.addons.k8s.io k8s-app: cluster-autoscaler rules: - apiGroups: [""] resources: ["configmaps"] verbs: ["create"] - apiGroups: [""] resources: ["configmaps"] resourceNames: ["cluster-autoscaler-status"] verbs: ["delete", "get", "update"] --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: name: cluster-autoscaler labels: k8s-addon: cluster-autoscaler.addons.k8s.io k8s-app: cluster-autoscaler roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-autoscaler subjects: - kind: ServiceAccount name: cluster-autoscaler namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: RoleBinding metadata: name: cluster-autoscaler namespace: kube-system labels: k8s-addon: cluster-autoscaler.addons.k8s.io k8s-app: cluster-autoscaler roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: cluster-autoscaler subjects: - kind: ServiceAccount name: cluster-autoscaler namespace: kube-system --- apiVersion: extensions/v1beta1 kind: Deployment metadata: name: cluster-autoscaler namespace: kube-system labels: app: cluster-autoscaler spec: replicas: 1 selector: matchLabels: app: cluster-autoscaler template: metadata: labels: app: cluster-autoscaler spec: serviceAccountName: cluster-autoscaler containers: - image: k8s.gcr.io/cluster-autoscaler:v1.2.2 name: cluster-autoscaler resources: limits: cpu: 100m memory: 300Mi requests: cpu: 100m memory: 300Mi command: - ./cluster-autoscaler - --v=4 - --stderrthreshold=info - --cloud-provider=aws - --skip-nodes-with-local-storage=false - --nodes=<MIN>:<MAX>:<ASG NAME> env: - name: AWS_REGION value: <AWS_REGION> volumeMounts: - name: ssl-certs mountPath: /etc/ssl/certs/ca-certificates.crt readOnly: true imagePullPolicy: "Always" volumes: - name: ssl-certs hostPath: path: "/etc/ssl/certs/ca-bundle.crt"
いくつか変更する必要があるパラメータがあります。
EC2 Auto Scalingの設定を元に設定してください。
- --nodes=<MIN>:<MAX>:<ASG NAME>
EKSが動いているリージョンを設定します。
env: - name: AWS_REGION value: <AWS_REGION>
applyします。
kubectl apply -f sample-ca.yaml
ログでスケールアップの計画を確認します。
kubectl logs -f deployment/cluster-autoscaler -n kube-system | grep "scale-up plan" I0423 02:23:07.675641 1 scale_up.go:292] Final scale-up plan: [{<ASG NAME> 3->4 (max: 6)}] I0423 02:24:21.913766 1 scale_up.go:292] Final scale-up plan: [{<ASG NAME> 4->5 (max: 6)}]
動作確認
EC2 Auto Scaling のコンソールで状態を確認してみます。
a user request explicitly set group desired capacity changing the desired capacity from 3 to 4.
ユーザーつまりCAからの要求によってdesired capacity
が変更されて、Autoscalingが発生しています。
Podの稼働状態を確認してみます。
kubectl get po NAME READY STATUS RESTARTS AGE sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 20m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 22m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 21m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 24m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 22m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 21m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 21m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 22m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 21m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 21m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 21m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 22m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 22m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 20m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 20m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 21m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 21m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 20m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 22m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 20m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 21m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 24m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 22m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 22m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 21m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 21m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 20m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 22m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 20m sample-deployment-xxxxxxxxx-xxxxx 1/1 Running 0 24m
すべてのSTATUSがRunning
です。
HPAは、targetAverageUtilization
で指定したメトリクスに収まる様にAutoscalingします。今回はCPU使用率 50%に設定したので、平均使用率が50%になるまでスケールアウトし続けます。
ですが、今回は100%に張り付く様にコマンドを指定しているので、いくらスケールアウトしても平均使用率は下がりません。
MAXPODS
に達してこれ以上スケールアウトが行われなくなりました。
kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE sample-hpa Deployment/sample-deployment 116%/50% 1 30 30 25m
CAによるスケールインを確認します。立ち上げたコンテナを全て終了させます。
kubectl delete -f sample-hpa.yaml
ログでスケールインの計画を確認します。
kubectl logs -f deployment/cluster-autoscaler -n kube-system | grep "Scale-down: removing" I0423 03:52:25.073390 1 scale_down.go:594] Scale-down: removing empty node ip-XX-X-XX-XXX.ap-northeast-1.compute.internal I0423 03:52:25.073425 1 scale_down.go:594] Scale-down: removing empty node ip-XX-X-XX-XXX.ap-northeast-1.compute.internal
あとがき
EKSでAutoscalingってどうするのか調べる必要があり、まとめてみました。 今回は適当ですが、metrics-serverなど、namespace: kube-system で動かすようなシステムリソースは専用のNodeGroup作ったほうが良いなと思いました。 また、スケールイン周りの動きの深いところが理解しきれていないです、CA→EC2 Auto Scalingに希望キャパシティを減らす命令を出す際に、CA側でどうやって削除されるインスタンスを特定しているのかなどがわかっていないです。
調べながらのブログ化だったので間違いもあるかも知れません、ツッコミや追記した方が良い情報があれば、ぜひコメントをお願います!
参考文献
1: Kubernetes 完全ガイド 著者 青山真也 発行所 株式会社インプレス ISBN978-4-295-00480-6 C3005